#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <glib.h>

#define BUF_SIZE 4096


/*
 * text_file_get_contents, get contents of file with path file_name
 * file_name: file path
 * return content of file with path file_name
 */
static char* text_file_get_contents(const char* file_name)
{
	GError* local_error = NULL;
	char* result = NULL;
	char* buf = NULL;

	// buf = (char*)malloc(BUF_SIZE);
	// if(!buf)
	// 	return NULL;

	// memset(buf, 0 , BUF_SIZE);

	if(!g_file_get_contents(file_name, &buf, NULL, &local_error))
		return NULL;

	result = strdup(buf);


	if(buf) {
		free(buf);
		buf = NULL;
	}

	if(local_error) {
		g_error_free(local_error);
		local_error = NULL;
	}
	
	return result;
}

/*
 * _remove_line_break, remove '\n' in str
 */
static void _remove_line_break(char* str)
{
	char* p;

	p = str;

	while(*p != '\0')
	{
		if(*p == '\n')
		{
			*p = '\0';
			break;
		}
		++p;
	}
}

/*
 * command_line_get_contents, get content of command line file, and remove '\n' in content
 * file_name: command line file path
 */
static char* command_line_get_contents(const char* file_name)
{
	char* cmdline = NULL;

	cmdline = text_file_get_contents(file_name);

	if(cmdline)
		_remove_line_break(cmdline);

	return cmdline;
}

/*
 * command_line_get_root, get root device from cmdline
 * cmdline: content of cmdline file
 */
static char* command_line_get_root(const char* cmdline)
{
	char copy[BUF_SIZE];
	char* delim = " \t";
	char* str = NULL;
	char* result = NULL;

	if(!cmdline)
		return NULL;

	memset(copy, 0, BUF_SIZE);
	memcpy(copy, cmdline, strlen(cmdline) + 1);

	str = strtok(copy, delim);
	if(!str)
		return NULL;

	if(strncmp(str, "root=", 5) == 0)
		return strdup(str);

	while((str = strtok(NULL, delim)) != NULL)
	{
		if(strncmp(str, "root=", 5) == 0) {
			result = strdup(str);
			break;
		}
	}

	return result;
}

/*
 * _root_label_convert, convert conv_from in src to conv_to and put content to dest
 * dest: destination string
 * src: source string
 * conv_from: content to convert
 * conv_to: content to convert to
 */
static void _root_label_convert(char* dest, char* src, char* conv_to, char* conv_from)
{
	char* p = NULL;
	char* q = NULL;
	char copy[BUF_SIZE];
	int to_length = 0;
	int from_length = 0;
	int count = 0;


	if(!dest || !src || !conv_to || !conv_from)
		return ;

	to_length = strlen(conv_to);
	from_length = strlen(conv_from);

	memset(copy, 0, BUF_SIZE);
	memcpy(copy, src, strlen(src));

	q = copy;

	while((p = strstr(q, conv_from)) != NULL)
	{
		*p = '\0';

		sprintf(&dest[count], "%s%s", q, conv_to);
		count += p - q + to_length;

		if(('\0' == *(p + from_length)))
		{
			q = p + from_length;
			break;
		}

		q = p + from_length;
	}

	if('\0' != *q)
		sprintf(&dest[count], "%s", q);
}

/*
 * command_line_root_get_device_name, get device name from cmdline_root
 */
static char* command_line_root_get_device_name(const char* cmdline_root)
{
	char* device_name = NULL;
	char copy[BUF_SIZE];
	char buf[BUF_SIZE];
	char* str = NULL;
	char* delim = "=";

	if(!cmdline_root)
		return NULL;

	memset(copy, 0, BUF_SIZE);
	memset(buf, 0, BUF_SIZE);
	memcpy(copy, cmdline_root, strlen(cmdline_root) + 1);

	str = strtok(copy, delim);
	if(!str)
		return NULL;

	while((str = strtok(NULL, delim)) != NULL)
	{
		char* tmp = NULL;
		char converted[BUF_SIZE];

		if(strcmp(str, "UUID") == 0)
		{
			tmp = strtok(NULL, delim);
			if(!tmp)
				return NULL;
			sprintf(buf, "/dev/disk/by-uuid/%s", tmp);
			device_name = strdup(buf);
			break;
		}
		else if(strcmp(str, "LABEL") == 0)
		{
			tmp = strtok(NULL, delim);
			if(!tmp)
				return NULL;

			memset(converted, 0, BUF_SIZE);
			_root_label_convert(converted, tmp, "\\x2f", "/");

			sprintf(buf, "/dev/disk/by-label/%s", converted);

			device_name = strdup(buf);
			break;
		}
		else {
			device_name = strdup(str);
			break;
		}
	}

	return device_name;
}

/*
 * command_line_get_root_device_name, get root device name from cmdline file
 */
char* command_line_get_root_device_name(const char* file_name)
{
	char* cmdline = NULL;
	char* root = NULL;
	char* root_device_name = NULL;

	cmdline = command_line_get_contents(file_name);

	if(!cmdline)
		return NULL;

	root = command_line_get_root(cmdline);
	if(!root)
		goto command_out;

	root_device_name = command_line_root_get_device_name(root);

command_out:
	if(cmdline)
		free(cmdline);
	if(root)
		free(root);

	return root_device_name;
}
